#include <string>
#include <vector>
#include "all.h"

void run_in_coroutine2() {
    LIBCO_LOG_INFO << "run_in_coroutine2 begin";
    LIBCO_LOG_INFO << "run_in_coroutine2 end";
}

void run_in_coroutine() {
    LIBCO_LOG_INFO << "run_in_coroutine begin";

    LIBCO_LOG_INFO << "before run_in_coroutine yield";
    libco::Coroutine::GetThis()->yield();
    LIBCO_LOG_INFO << "after run_in_coroutine yield";

    LIBCO_LOG_INFO << "run_in_coroutine end";
    // coroutine结束之后会自动返回主协程运行
}

void test_coroutine() {
    LIBCO_LOG_INFO << "test_coroutine begin";

    // 初始化线程主协程
    libco::Coroutine::GetThis();
    // std::cout << tmp.use_count() << std::endl;

    libco::Coroutine::ptr coroutine(new libco::Coroutine(run_in_coroutine, 0));
    LIBCO_LOG_INFO << "use_count:" << coroutine.use_count(); // 1

    LIBCO_LOG_INFO << "before test_coroutine resume";
    coroutine->resume();
    LIBCO_LOG_INFO << "after test_coroutine resume";

    /** 
     * 关于coroutine智能指针的引用计数为3的说明：
     * 一份在当前函数的coroutine指针，一份在MainFunc的cur指针
     * 还有一份在在run_in_coroutine的GetThis()结果的临时变量里
     */
    LIBCO_LOG_INFO << "use_count:" << coroutine.use_count(); // 3

    LIBCO_LOG_INFO << "coroutine status: " << coroutine->getState(); // READY

    LIBCO_LOG_INFO << "before test_coroutine resume again";
    coroutine->resume();
    LIBCO_LOG_INFO << "after test_coroutine resume again";

    LIBCO_LOG_INFO << "use_count:" << coroutine.use_count(); // 1
    LIBCO_LOG_INFO << "coroutine status: " << coroutine->getState(); // TERM

    coroutine->reset(run_in_coroutine2); // 上一个协程结束之后，复用其栈空间再创建一个新协程
    coroutine->resume();

    LIBCO_LOG_INFO << "use_count:" << coroutine.use_count(); // 1
    LIBCO_LOG_INFO << "test_coroutine end";
}

int main(int argc, char *argv[]) {
    libco::SetThreadName("main_thread");
    LIBCO_LOG_INFO << "main begin";

    std::vector<libco::Thread::ptr> thrs;
    for (int i = 0; i < 4; i++) {
        thrs.push_back(libco::Thread::ptr(
            new libco::Thread(&test_coroutine, "thread_" + std::to_string(i))));
    }

    for (auto i : thrs) {
        i->join();
    }

    LIBCO_LOG_INFO << "main end";
    return 0;
}